/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.picasso;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.NetworkInfo;
import java.io.IOException;
import java.io.InputStream;

import static com.squareup.picasso.Downloader.Response;
import static com.squareup.picasso.Picasso.LoadedFrom.DISK;
import static com.squareup.picasso.Picasso.LoadedFrom.NETWORK;

class NetworkBitmapHunter extends BitmapHunter {
	static final int DEFAULT_RETRY_COUNT = 2;
	private static final int MARKER = 65536;

	private final Downloader downloader;

	int retryCount;

	@SuppressWarnings("rawtypes")
	public NetworkBitmapHunter(Picasso picasso, Dispatcher dispatcher,
			Cache cache, Stats stats, Action action, Downloader downloader) {
		super(picasso, dispatcher, cache, stats, action);
		this.downloader = downloader;
		this.retryCount = DEFAULT_RETRY_COUNT;
	}

	@Override
	Bitmap decode(Request data) throws IOException {
		boolean loadFromLocalCacheOnly = retryCount == 0;

		Response response = downloader.load(data.uri, loadFromLocalCacheOnly);
		if (response == null) {
			return null;
		}

		loadedFrom = response.cached ? DISK : NETWORK;

		Bitmap result = response.getBitmap();
		if (result != null) {
			return result;
		}

		InputStream is = response.getInputStream();
		if (is == null) {
			return null;
		}
		if (loadedFrom == NETWORK && response.getContentLength() > 0) {
			stats.dispatchDownloadFinished(response.getContentLength());
		}
		try {
			return decodeStream(is, data);
		} finally {
			Utils.closeQuietly(is);
		}
	}

	@Override
	boolean shouldRetry(boolean airplaneMode, NetworkInfo info) {
		boolean hasRetries = retryCount > 0;
		if (!hasRetries) {
			return false;
		}
		retryCount--;
		return info == null || info.isConnectedOrConnecting();
	}

	private Bitmap decodeStream(InputStream stream, Request data)
			throws IOException {
		MarkableInputStream markStream = new MarkableInputStream(stream);
		stream = markStream;

		long mark = markStream.savePosition(MARKER);

		final BitmapFactory.Options options = createBitmapOptions(data);
		final boolean calculateSize = requiresInSampleSize(options);

		boolean isWebPFile = Utils.isWebPFile(stream);
		markStream.reset(mark);
		// When decode WebP network stream, BitmapFactory throw JNI Exception
		// and make app crash.
		// Decode byte array instead
		if (isWebPFile) {
			byte[] bytes = Utils.toByteArray(stream);
			if (calculateSize) {
				BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
				calculateInSampleSize(data.targetWidth, data.targetHeight,
						options);
			}
			return BitmapFactory.decodeByteArray(bytes, 0, bytes.length,
					options);
		} else {
			if (calculateSize) {
				BitmapFactory.decodeStream(stream, null, options);
				calculateInSampleSize(data.targetWidth, data.targetHeight,
						options);

				markStream.reset(mark);
			}
			return BitmapFactory.decodeStream(stream, null, options);
		}
	}
}
